﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Puzzle
{
    public partial class Board
    {
        public void swapRotateSinglePiece(uint numOfTimes = 1, bool swap = true, bool rotate = true)
        {
            for (int i = 0; i < numOfTimes; i++)
            {
                Random ran = new Random();
                int index1 = ran.Next(0, 100);
                int index2 = ran.Next(0, 100);
                int numOfRotations = ran.Next(0, 3);
                
                if (swap == true)
                {
                    swapPieces(index1, index2);
                }
                if (rotate == true)
                {
                    rotatePiece(index1, numOfRotations);
                    rotatePiece(index2, numOfRotations);
                }
            }
        }
        public void swapRotate_ConserveEdgeIntegrity(uint iterations)
        {
            for (int i = 0; i < iterations; i++)
            {
                Random ran = new Random();
                int index1 = ran.Next(0, 100);
                if (onEdge(index1) == true) //if index1 is on the edge (this does not include corners)
                {
                    if (this.tiles[index1].isEdgePiece())
                    //if index1 is itself an edge piece, it should only swap with another edge piece (wherever this edge piece may be)
                    {
                        int index2;
                        do
                        {
                            index2 = ran.Next(0, 100);
                        }
                        while (!(this.tiles[index2].isEdgePiece()));

                        swapPieces(index1, index2);
                        if(onEdge(index2))
                            rotateEdgePieceCorrectly(index2);
                        rotateEdgePieceCorrectly(index1);
                    }
                    else if (this.tiles[index1].isCornerPiece()) //index1 is a corner piece but is currently placed on the edge; it'll be swapped with a piece present in a corner but that is not a corner piece
                    {
                        int[] corners = new int[4] { 0, 9, 90, 99 };

                        int index2;
                        do
                        {
                            index2 = ran.Next(0, 4);
                            index2 = corners[index2];
                        }
                        while (this.tiles[index2].isCornerPiece());

                        swapPieces(index1, index2);
                        rotateCornerPieceCorrectly(index2);
                    }
                    else
                    {
                        int index2;
                        do
                        {
                            index2 = ran.Next(0, 99);
                        }
                        while (whichEdge(index2) != edgePlacement.none);
                        swapPieces(index1, index2);
                        rotatePiece(index1, ran.Next(0, 3));
                        
                    }

                }
                else if (onCorner(index1) == true)
                { //if the piece is on the corner but is not a corner piece (so it's a edge or center piece), do nothing! yay
                    if (this.tiles[index1].isCornerPiece()) //just swap with another corner piece
                    {
                        int[] corners = new int[4] { 0, 9, 90, 99 };
                        int index2 = ran.Next(0, 3);
                        index2 = corners[index2];
                        swapPieces(index1, index2);
                        //rotateCornerPieceCorrectly(index1);
                        rotateCornerPieceCorrectly(index2);
                    }
                }
                else
                {
                    if(this.tiles[index1].isEdgePiece())
                    {//exchange this edge piece in the middle of the board with a piece on the edge that's not supposed to be there
                        int index2;
                        do
                        {
                            index2 = (int)getIndexPieceOnEdge();


                        }
                        while(this.tiles[index2].isEdgePiece());

                        swapPieces(index1, index2);
                    }
                    else if (this.tiles[index1].isCornerPiece())
                    {
                        int index2;
                        do
                        {
                            index2 = (int)getIndexPieceOnCorner();

                        }
                        while (this.tiles[index2].isCornerPiece());

                        swapPieces(index2, index1);

                    }
                    else
                    {
                        int index2;
                        do //get a piece from the center of the board
                        {
                            index2 = (int)getIndexPieceInMiddle();
                        }
                        while (whichEdge(index2) != edgePlacement.none);

                        swapPieces(index1, index2);
                        int numOfRotations = ran.Next(0, 3);
                        rotatePiece(index1, numOfRotations);
                        rotatePiece(index2, numOfRotations);
                    }

                }

                //int index2 = ran.Next(0, 99);

                /*
                index1 is on edge
                   index1 is an edge piece -> index2 will be a random piece on the edge
                   index1 is a corner piece -> swaps with any corner piece
                   index1 is not an edge piece -> non-edge swap

                 index1 is on a corner
                    it's a edge piece -> do nothin'
                    corner piece yo -> swap with any corner
                    it's a center piece -> do nothing 4ever yolo
                 
                index1 is not on edge
                   edge piece -> index2 must be an edge piece that's not supposed to be there
                   not edge piece -> non-edge swap
                 */
                 
            }
        }


        public void swapRotateOnlyMiddlePiecesFewNeighbors(uint iterations, uint mininumNeighbors)
        {
            
            for (int i = 0; i < iterations; i++)
            {
                int index1;
                int index2;
                int count = 0;
                do
                {
                    index1 = (int)getIndexPieceInMiddle();
                    count++;
                    if(count == 200)
                        return;

                }
                while(tileMatchingNeighbor(index1) >= mininumNeighbors);

                count = 0;
                do
                {
                    index2 = (int)getIndexPieceInMiddle();
                    count++;
                    if (count == 200)
                        return;

                }
                while (tileMatchingNeighbor(index2) >= mininumNeighbors);

                swapPieces(index1, index2);
                rotatePiece(index1,count%4);
                rotatePiece(index2,count %4);
            }
        }

        public void swapOnlyCornerPieces(uint iterations)
        {

            int index1;
            int index2;
            for (int i = 0; i < iterations; i++)
            {
                index1 = (int)getIndexPieceOnCorner();
                index2 = (int)getIndexPieceOnCorner();
                swapPieces(index1, index2);
                if (this.tiles[index1].isCornerPiece())
                    rotateCornerPieceCorrectly(index1);
                if (this.tiles[index2].isCornerPiece())
                    rotateCornerPieceCorrectly(index2);
            }

        }

        public void swapOnlyEdgePieces(uint iterations)
        {


            int index1;
            int index2;
            for (int i = 0; i < iterations; i++)
            {
                index1 = (int)getIndexPieceOnEdge();
                index2 = (int)getIndexPieceOnEdge();
                swapPieces(index1, index2);
                if (this.tiles[index1].isEdgePiece())
                    rotateEdgePieceCorrectly(index1);
                if (this.tiles[index2].isEdgePiece())
                    rotateEdgePieceCorrectly(index2);
            }
        }

        public void swapRotate2CentrePieces(uint numOfPairs)
        {
            int index1;
            int index2;
            Random ran = new Random();
            for (int i = 0; i < numOfPairs; i++)
            {
                index1 = (int)getIndexPieceInMiddle();
                index2 = (int)getIndexPieceInMiddle();
                swapPieces(index1, index2);
                rotatePiece(index1, ran.Next(0,4));
                rotatePiece(index2, ran.Next(0,4));
            }
        }

        public void slideBlock2x2OfMatchingPieces(uint attemptsToFindBlock)
        {
            
            int index1;
            int index2;
            for (int i = 0; i < attemptsToFindBlock; i++)
            {
                index1 = get2x2TopLeftCorner();
                index2 = get2x2TopLeftCorner();
                if (isValid2x2Block(index1))
                {
                    move2x2Block(index1, index2);
                }
                else if (isValid2x2Block(index2))
                {
                    move2x2Block(index2, index1);
                }
            }
        }

        
        private void swapPieces(int first, int second)
        {
            Tile temp = this.tiles[first];
            this.tiles[first] = this.tiles[second];
            this.tiles[second] = temp;
        }
        public void move2x2Block(int index1, int index2)
        {
            swapPieces(index1, index2);
            swapPieces(index1 + 1, index2 + 1);
            swapPieces(index1 + 10, index2 + 10);
            swapPieces(index1 + 11, index2 + 11);

        }
        public bool isValid2x2Block(int topLeftTile)
        {
            if (this.tiles[topLeftTile].bottom == this.tiles[topLeftTile + 10].top)
            {
                if (this.tiles[topLeftTile].right == this.tiles[topLeftTile + 1].left)
                {
                    if (this.tiles[topLeftTile + 11].left == this.tiles[topLeftTile + 10].right)
                    {
                        if (this.tiles[topLeftTile + 11].top == this.tiles[topLeftTile + 1].bottom)
                            return true;
                    }
                }
            }
            return false;

        }
        private void rotatePiece(int index, int numOfRotations)
        {
            for (int i = 0; i < numOfRotations; i++)
            {
                int temp = this.tiles[index].top;
                this.tiles[index].top = this.tiles[index].left;
                this.tiles[index].left = this.tiles[index].bottom;
                this.tiles[index].bottom = this.tiles[index].right;
                this.tiles[index].right = temp;
            }
        }
        public static int get2x2TopLeftCorner()
        {
            Random ran = new Random();
            int ret;
            do
            {
                ret = ran.Next(11, 78);
            }
            while(ret == 68 || ret == 58 || ret == 48 || ret == 38 ||ret == 28||ret == 18);
            return ret;
        }
        public void rotateAllEdges()
        {
            int[] edges = new int[32] {1,2,3,4,5,6,7,8,10,20,30,40,50,60,70,80,19,29,39,49,59,69,79,89,91,92,93,94,95,96,97,98};

            for (int i = 0; i < 32; i++)
            {
                if(!(onEdge(edges[i])))
                    throw new CustomExc("in rotateAllEdges(), the index is not the position on the edge");
                if (this.tiles[edges[i]].isEdgePiece())
                    rotateEdgePieceCorrectly(edges[i]);
            }
        }
        public void rotateAllCorners()
        {
            int[] corners = new int[4] {0,9,90,99 };
            for (int i = 0; i < 4; i++)
            {
                if (!(onCorner(corners[i])))
                    throw new CustomExc("in rotateAllCorners(), the index is not a position of the corner");

                if (this.tiles[corners[i]].isCornerPiece())
                    rotateCornerPieceCorrectly(corners[i]);
            }
        }

    }
}
